﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;

namespace hydratingOld
{
	/// <summary>
	/// this class is for .NET 2.0 with reflection instead of recursion
	/// </summary>
	/// <typeparam name="T"></typeparam>
	public class HydrateGeneric_Net2<T>
		where T : class,new()
	{
		private Dictionary<string,PropertyInfo[]> properties;
		
		private Dictionary<string, string> Modified;
		public HydrateGeneric_Net2()
		{
			properties = new Dictionary<string, PropertyInfo[]>();
			List<PropertyInfo> props=new List<PropertyInfo>();
			foreach (var item in typeof(T).GetProperties())
			{
				if (item.CanWrite)
					props.Add(item);
			}
			properties.Add(typeof(T).FullName, props.ToArray());
			
			Modified = new Dictionary<string, string>();
		}

		private void SetPropRecursive(Type t, string PropName, object o, string value)
		{
			string key = t.FullName;
			if (!properties.ContainsKey(key))
			{
				List<PropertyInfo> propsInfo = new List<PropertyInfo>();
				foreach (var item in t.GetProperties())
				{
					if (item.CanWrite)
                        propsInfo.Add(item);
				}
                properties.Add(key, propsInfo.ToArray());
			}
			var props = properties[key];
			int dot = PropName.IndexOf(".");
			string realNameProp = (dot > -1) ? PropName.Substring(0, dot) : PropName;
            PropertyInfo prop = null;
            foreach (var item in props)
            {
                if(item.Name == realNameProp){
                    prop=item;
                    break;
                }
                    
            }			
			if (prop == null)
			{
				throw new ArgumentException(String.Format("object {0} does not have writable prop:{1}", key, PropName));
			}

			if (dot > -1)
			{
				SetPropRecursive(prop.PropertyType, PropName.Substring(dot + 1), prop.GetValue(o,null), value);
				return;
			}
			//finaly a clear prop
			try
			{
				var newval = Convert.ChangeType(value, prop.PropertyType);
				prop.SetValue(o, newval, null);
			}
			catch (Exception ex)
			{
				//convert.changetype
				Type exType = ex.GetType();
				if (exType == typeof(System.FormatException)
						|| exType == typeof(System.OverflowException)
					   || exType == typeof(System.InvalidCastException)
					   || exType == typeof(System.ArgumentException)
				)
				{
					throw new ArgumentException("value " + value + " can not be converted to :" + prop.PropertyType.FullName, ex);
				}
				throw;
			}
		}
		/// <summary>
		/// add a new property with his value
		/// e.g. "Employee.FirstName","Andrei"
		/// </summary>
		/// <param name="NameProp">can be Employee.FirstName</param>
		/// <param name="value">can be Andrei</param>
		public void AddNewProperty(string NameProp, string value)
		{
			Modified.Add(NameProp, value);
			
		}
		
		
		/// <summary>
		/// constructs the new object from properties
		/// </summary>
		/// <returns></returns>
		public T NewObject()
		{
            T Existing = new T();
			foreach (var item in Modified)
			{
				SetPropRecursive(typeof(T), item.Key, Existing, item.Value);
			}
            return Existing;
		}
		
	}
}
